// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENCRYPTED_REPORTING_JOB_CONFIGURATION_H_
#define COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENCRYPTED_REPORTING_JOB_CONFIGURATION_H_

#include <memory>
#include <string>

#include "base/functional/callback.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/reporting_job_configuration_base.h"
#include "components/policy/policy_export.h"
#include "components/reporting/proto/synced/record_constants.pb.h"

namespace policy {

// {{{Note}}} ERP Request Payload Overview
//
// EncryptedReportingJobConfiguration configures a payload for the Encrypted
// server endpoint. A JSON version of the payload looks like this:
// {
//   "encryptedRecord": [
//     {
//       "encryptedWrappedRecord": "EncryptedMessage",
//       "encryptionInfo" : {
//         "encryptionKey": "LocalPublicValue",
//         "publicKeyId": 1
//       },
//       "sequenceInformation": {
//         "sequencingId": 1,
//         "generationId": 123456789,
//         "priority": 1
//       },
//       "compressionInformation": {
//         "compressionAlgorithm": 1
//       }
//     },
//     {
//       "encryptedWrappedRecord": "EncryptedMessage",
//       "encryptionInfo" : {
//         "encryptionKey": "LocalPublicValue",
//         "publicKeyId": 2
//       },
//       "sequenceInformation": {
//         "sequencingId": 2,
//         "generationId": 123456789,
//         "priority": 1
//       },
//       "compressionInformation": {
//         "compressionAlgorithm": 1
//       }
//     }
//   ],
//   "attachEncryptionSettings": true,  // optional field
//   "requestId": "SomeString",
//   "device": {
//     "client_id": "abcdef1234",
//     "dmToken": "abcdef1234",
//     "name": "George",
//     "osPlatform": "Windows",
//     "osVersion": "10.0.0.0"
//   },
//   "browser": {
//     "browserId": "abcdef1234",
//     "chromeVersion": "10.0.0.0",
//     "machineUser": "abcdef1234",
//     "userAgent": "abcdef1234"
//   }
// }
// "device" and "browser" are populated by the base class,
// the rest needs to be provided as |merging_payload|.
//
// Details other than the "device" and "browser" fields are documented at note
// "ERP Encrypted Record".

class POLICY_EXPORT EncryptedReportingJobConfiguration
    : public ReportingJobConfigurationBase {
 public:
  EncryptedReportingJobConfiguration(
      scoped_refptr<network::SharedURLLoaderFactory> factory,
      DMAuth auth_data,
      const std::string& server_url,
      base::Value::Dict merging_payload,
      const std::string& dm_token,
      const std::string& client_id,
      UploadCompleteCallback complete_cb);
  ~EncryptedReportingJobConfiguration() override;

  // |context| is a base::Value::Dict item as generated by
  // |reporting::GetContext|.  |context| will be stored and applied to the
  // payload on the proceeding |GetPayload| call. |context| mostly fills out the
  // profile dictionary, but does overwrite a few of the device and browser
  // fields (check reporting::GetContext for specifics).
  void UpdateContext(base::Value::Dict context);

  // Checks the new job against the history, determines how soon the upload will
  // be allowed. Returns positive value if not allowed, and 0 or negative
  // otherwise.
  base::TimeDelta WhenIsAllowedToProceed() const;

  // Account for the job, that was allowed to proceed.
  void AccountForAllowedJob();

  // Cancels the job, that was not allowed to proceed.
  void CancelNotAllowedJob();

  // Callback to process error codes and, in case of success, response body.
  void OnURLLoadComplete(DeviceManagementService::Job* job,
                         int net_error,
                         int response_code,
                         const std::string& response_body) override;

  // Test-only method that resets collected uploads state.
  static void ResetUploadsStateForTest();

 protected:
  void UpdatePayloadBeforeGetInternal() override;

  // DeviceManagementService::JobConfiguration
  DeviceManagementService::Job::RetryMethod ShouldRetry(
      int response_code,
      const std::string& response_body) override;

  std::string GetUmaString() const override;

 private:
  std::set<std::string> GetTopLevelKeyAllowList();

  // Parameters populated from the payload_.
  ::reporting::Priority priority_;
  int64_t generation_id_{-1};
  int64_t sequence_id_{-1};
};

}  // namespace policy

#endif  // COMPONENTS_POLICY_CORE_COMMON_CLOUD_ENCRYPTED_REPORTING_JOB_CONFIGURATION_H_
